package map;


import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

public class GridPointAllocator {

    private static final double MIN_DISTANCE_SQUARED = 400; // 20^2 for efficiency in distance check
    private static final Random RANDOM = new Random();
    private static final Map<String, Integer> CATEGORY_COUNTS = new HashMap<>();
    static {
        CATEGORY_COUNTS.put("city", 2400);
        CATEGORY_COUNTS.put("monster", 6000);
        CATEGORY_COUNTS.put("gather", 3200);
        CATEGORY_COUNTS.put("kacoscomp", 2400);
    }
    private static final double MAP_START = -1700.0;
    private static final double MAP_END = 1700.0;
    private static final Set<Point> allPoints = new HashSet<>();

    public static void main(String[] args) {
        Map<String, List<Point>> allocatedPoints = new HashMap<>();
        for (String category : CATEGORY_COUNTS.keySet()) {
            allocatedPoints.put(category, allocatePoints(CATEGORY_COUNTS.get(category), category));
        }

        writePointsToJson(allocatedPoints, "points2.json");
    }

    private static List<Point> allocatePoints(int count, String category) {
        List<Point> points = new ArrayList<>();
        while (points.size() < count) {
            double x = getRandomPosition(MAP_START, MAP_END);
            double y = getRandomPosition(MAP_START, MAP_END);
            Point newPoint = new Point(Math.round(x * 10) / 10.0, Math.round(y * 10) / 10.0);

            boolean isSafeToAdd = true;
            for (Point existingPoint : allPoints) {
                if (calculateDistanceSquared(existingPoint, newPoint) < MIN_DISTANCE_SQUARED) {
                    isSafeToAdd = false;
                    break;
                }
            }

            if (isSafeToAdd) {
                points.add(newPoint);
                allPoints.add(newPoint);
            }
        }
        return points;
    }

    private static double getRandomPosition(double start, double end) {
        return start + (end - start) * RANDOM.nextDouble();
    }

    private static double calculateDistanceSquared(Point p1, Point p2) {
        double dx = p1.x - p2.x;
        double dy = p1.y - p2.y;
        return dx*dx + dy*dy;
    }

    private static void writePointsToJson(Map<String, List<Point>> points, String filename) {
        try (FileWriter file = new FileWriter(filename)) {
            file.write("{\n");
            boolean firstKey = true;
            for (Map.Entry<String, List<GridPointAllocator.Point>> entry : points.entrySet()) {
                if (!firstKey) {
                    file.write(",\n");
                }
                firstKey = false;
                file.write("    \"" + entry.getKey() + "\": [\n");

                boolean firstPoint = true;
                for (GridPointAllocator.Point p : entry.getValue()) {
                    if (!firstPoint) {
                        file.write(",\n");
                    }
                    firstPoint = false;
                    file.write("        {\"x\": " + p.x + ", \"y\": " + p.y + "}");
                }
                file.write("\n    ]");
            }
            file.write("\n}");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class Point {
        double x;
        double y;

        Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    }
}
